from decimal import Decimal

from django.db import transaction
from django_redis import get_redis_connection
from rest_framework import serializers

from goods.models import SKU


class CartSKUSerializer(serializers.Serializer):
    """"""
    """
    购物车商品数据序列化
    """
    count=serializers.IntegerField(label='数量')

    class Meta:
        model=SKU
        fields=('id','name','default_image_url','price','count')


class PlaceOrderSerializer(serializers.Serializer):

    freight=serializers.DecimalField(label='运费',decimal_places=2,max_digits=10)
    skus=CartSKUSerializer(many=True)


from orders.models import OrderInfo


class OrderSerializer(serializers.ModelSerializer):

    class Meta:
        model=OrderInfo
        fields=('order_id','address','pay_method')
        read_only_fields=('order_id')
        extra_kwargs={
            'address':{
                'write_only':True,
                'required':True
            },
            'pay_method':{
                'write_only':True,
                'required':True
            }
        }

    def create(self, validated_data):

        user=self.context['request'].user

        address=validated_data.get('address')

        from django.utils import timezone

        order_id=timezone.now().strftime('%Y%m%d%H%M%S')+'%09d'%user.id

        total_count=0
        total_amount=Decimal('0')
        freight=Decimal('10.00')

        pay_method=validated_data.get('pay_method')

        if pay_method==OrderInfo.PAY_METHODS_ENUM['CASH']:
            status=OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        else:
            status=OrderInfo.ORDER_STATUS_ENUM['UNPAID']

        with transaction.atomic():
            save_id=transaction.savepoint()
            try:

                order=OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=total_count,
                    total_amount=total_amount,
                    freight=freight,
                    pay_method=pay_method,
                    status=status
                )

                redis_conn=get_redis_connection('cart')
                cart_redis=redis_conn.hgetall('cart_%s'%user.id)
                cart_selected=redis_conn.smembers('cart_selected_%s'%user.id)

                cart={}
                for sku_id in cart_selected:
                    cart[int(sku_id)]=int(cart_redis[sku_id])

                sku_id_list=cart.keys()


                for sku_id in sku_id_list:
                    sku=SKU.objects.get(pk=sku_id)
                    count=cart[sku.id]
                    if sku.stock<count:
                        raise serializers.ValidationError('库存不足')


                    print(sku.stock)
                    import time
                    time.sleep(5)
                    sku.stock-=count
                    sku.sales+=count
                    sku.save()

                    origin_stock=sku.stock

                    origin_sales=sku.sales

                    new_stock=origin_stock-count
                    new_sales=origin_sales+count

                    result=SKU.objects.filter(id=sku.id,stock=origin_stock).update(stock=new_stock,sales=new_sales)
                    if result==0:
                        continue

                    order.total_count+=count
                    order.total_amount+=(sku.price*count)

                    OrderInfo.objects.create(
                        order=order,
                        sku=sku,
                        count=count,
                        price=sku.price
                    )
                    break

                order.save()
            except ValueError:
                raise
            except Exception as e:
                transaction.savepoint_rollback(save_id)
                raise serializers.ValidationError("下单失败")
            transaction.savepoint_commit(save_id)
            pl=redis_conn.pipeline()
            pl.hdel('cart_%s'%user.id,*cart_selected)
            pl.srem('cart_selected_%s'%user.id,*cart_selected)
            pl.excute()

            return order

